package utils

/*
大数加法，只适用于整数
*/
func doBigIntegerPlus(n1 []int8, n2 []int8) []int8 {
	var res []int8
	if isNegative(n1) {
		if isNegative(n2) {
			//负数加负数
			res = setNegative(bigIntegerPlus0(setPositive(n1), setPositive(n2)))
		} else {
			//负数加正数
			res = bigIntegerSub0(n2, setPositive(n1))
		}
	} else {
		if isNegative(n2) {
			//正数加负数
			res = bigIntegerSub0(n1, setPositive(n2))
		} else {
			//正数加正数
			res = bigIntegerPlus0(n1, n2)
		}
	}
	return res
}

/*
大数减法，只适用于整数
*/
func doBigIntegerSub(n1 []int8, n2 []int8) []int8 {
	var res []int8
	if isNegative(n1) {
		if isNegative(n2) {
			//负数减负数
			res = bigIntegerSub0(setPositive(n2), setPositive(n1))
		} else {
			//负数减正数
			res = setNegative(bigIntegerPlus0(setPositive(n1), n2))
		}
	} else {
		if isNegative(n2) {
			//正数减负数
			res = bigIntegerPlus0(n1, setPositive(n2))
		} else {
			//正数减正数
			res = bigIntegerSub0(n1, n2)
		}
	}
	return res
}

/*
大数乘法，只适用于整数
*/
func doBigIntegerMultiply(n1 []int8, n2 []int8) []int8 {
	var res []int8
	if isNegative(n1) {
		if isNegative(n2) {
			//负数乘负数
			res = bigIntegerMultiply0(setPositive(n1), setPositive(n2))
		} else {
			//负数乘正数
			res = setNegative(bigIntegerMultiply0(setPositive(n1), n2))
		}
	} else {
		if isNegative(n2) {
			//正数乘负数
			res = setNegative(bigIntegerMultiply0(n1, setPositive(n2)))
		} else {
			//正数乘正数
			res = bigIntegerMultiply0(n1, n2)
		}
	}
	return res
}

/*
大数除法，只适用于整数
*/
func doBigIntegerDivide(n1 []int8, n2 []int8) ([]int8, []int8) {
	if isZero(n2) || isZero(setPositive(n2)) {
		panic("除数不能为零")
	}
	var r1, r2 []int8
	if isNegative(n1) {
		if isNegative(n2) {
			//负数除负数
			r1, r2 = bigIntegerDivide0(setPositive(n1), setPositive(n2))
			if !equals(r2, ZERO) {
				r2 = setNegative(r2)
			}
		} else {
			//负数除正数
			r1, r2 = bigIntegerDivide0(setPositive(n1), n2)
			if !equals(r1, ZERO) {
				r1 = setNegative(r1)
			}
			if !equals(r2, ZERO) {
				r2 = setNegative(r2)
			}
		}
	} else {
		if isNegative(n2) {
			//正数除负数
			r1, r2 = bigIntegerDivide0(n1, setPositive(n2))
			if !equals(r1, ZERO) {
				r1 = setNegative(r1)
			}
		} else {
			//正数除正数
			r1, r2 = bigIntegerDivide0(n1, n2)
		}
	}
	return r1, r2
}

/*
大数加法，只适用于正整数
*/
func bigIntegerPlus0(n1 []int8, n2 []int8) []int8 {
	n1, n2 = dropArrHeadZero(n1), dropArrHeadZero(n2)
	l1, l2 := len(n1), len(n2)
	if l1 < l2 {
		return bigIntegerPlus0(n2, n1)
	}

	res := make([]int8, l1+1)
	i := 0
	for ; i < l2; i++ {
		temp := n1[l1-i-1] + n2[l2-i-1] + res[l1-i]
		if temp > 9 {
			res[l1-i-1]++
			res[l1-i] = temp - 10
		} else {
			res[l1-i] = temp
		}
	}
	for ; i < l1; i++ {
		res[l1-i] += n1[l1-i-1]
		if res[l1-i] > 9 {
			res[l1-i] -= 10
			res[l1-i-1]++
		}
	}
	if res[0] == 0 {
		res = res[1:]
	}
	return res
}

/*
大数减法，只适用于正整数
*/
func bigIntegerSub0(n1 []int8, n2 []int8) []int8 {
	n1, n2 = dropArrHeadZero(n1), dropArrHeadZero(n2)
	if smallerThan(n1, n2) {
		sub := bigIntegerSub0(n2, n1)
		return setNegative(sub)
	}

	l1, l2 := len(n1), len(n2)
	res := make([]int8, l1+1)
	i := 0
	for ; i < l2; i++ {
		temp := res[l1-i] + n1[l1-1-i] - n2[l2-1-i]
		if temp < 0 {
			res[l1-i] = temp + 10
			res[l1-1-i]--
		} else {
			res[l1-i] = temp
		}
	}
	for ; i < l1; i++ {
		temp := res[l1-i] + n1[l1-1-i]
		if temp < 0 {
			res[l1-i] += 10
			res[l1-1-i]--
		} else {
			res[l1-i] = temp
		}
	}
	if res[0] == 0 {
		res = res[1:]
	}
	return res
}

/*
大数乘法，只适用于正整数
*/
func bigIntegerMultiply0(n1 []int8, n2 []int8) []int8 {
	n1, n2 = dropArrHeadZero(n1), dropArrHeadZero(n2)
	l1, rLen := len(n1), len(n1)+len(n2)
	res := make([]int8, rLen)

	for i := 0; i < l1; i++ {
		temp := integerMultiply(n2, n1[l1-1-i], i)
		res = bigIntegerPlus0(res, temp)
	}
	return res
}

/*
大数除法，只适用于正整数
*/
func bigIntegerDivide0(n1 []int8, n2 []int8) ([]int8, []int8) {
	n1, n2 = dropArrHeadZero(n1), dropArrHeadZero(n2)
	if smallerThan(n1, n2) {
		return ZERO, n1
	}
	if equals(n1, n2) {
		return ONE, ZERO
	}
	l1, l2 := len(n1), len(n2)
	res := make([]int8, l1)
	index, reminder, remindBitLen := 0, n1, l1-l2
	for remindBitLen >= 0 {
		//补充0的位数
		divideTemp := appendTailZero(n2, remindBitLen)
		//第一次减的余数
		firstReminder := bigIntegerSub0(reminder, divideTemp)
		var multiple int8 = 0
		if isPositive(firstReminder) {
			multiple = 1
			reminder = firstReminder
			for isPositive(reminder) {
				temp := bigIntegerSub0(reminder, divideTemp)
				if isNegative(temp) {
					break
				}
				multiple++
				reminder = temp
			}
		}
		res[index] = multiple
		index++
		remindBitLen--
	}
	return res[:index], reminder
}
